package com.wzm.api;


import com.wzm.pojo.Error;
import com.wzm.pojo.Result;
import com.wzm.pojo.Rsp;
import io.restassured.path.json.JsonPath;
import io.restassured.response.Response;
import org.hamcrest.Matchers;
import org.testng.Assert;

import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;

public class HTTPRspUtils {

    public final Logger logger = Logger.getLogger(this.getClass().getName());

    public static <T> Rsp<T> parseRspRst(Response httpRsp, Class<T> objectType) {
        return parseRspRst(httpRsp, "$", objectType, true);
    }

    public static <T> Rsp<T> parseRspRst(Response httpRsp, Class<T> objectType, boolean isObject) {
        return parseRspRst(httpRsp, "$", objectType, isObject);
    }

    public static <T> Rsp<T> parseRspRst(Response httpRsp, String targetPath, Class<T> objectType) {
        return parseRspRst(httpRsp, targetPath,objectType, true);
    }

    //后期备用自定义提取
    public static <T> Rsp<T> parseRspRst(Response httpRsp, String targetPath, Class<T> objectType, boolean isObject) {
        Rsp<T> rsp = new Rsp<>();
        int statusCode = httpRsp.statusCode();
        rsp.setCode(statusCode);

        if (statusCode >= 200 && statusCode < 300) {
            rsp.setSuccess(true);
            //提取的响应值给Rst
            rsp.setRst(HTTPRspUtils.extractObjectFromResponse(httpRsp, targetPath, objectType, isObject));
        } else {
            List<Error> errors = HTTPRspUtils.extractRspError(httpRsp);
            rsp.setErrors(errors);
            rsp.setSuccess(false);
        }
        return rsp;
    }

    //适用于当前系统解析响应体
    public static <T> Rsp<T> parseRspRst(Response httpRsp){
        Rsp<T> rsp = new Rsp<>();
        if (httpRsp != null){
            rsp.setCode(Integer.parseInt(HTTPRspUtils.extractStringResponse(httpRsp,"code")));
            rsp.setSuccess(Boolean.parseBoolean(HTTPRspUtils.extractStringResponse(httpRsp,"success")));
            rsp.setMessage(HTTPRspUtils.extractStringResponse(httpRsp,"message"));
            rsp.setTimestamp(HTTPRspUtils.extractStringResponse(httpRsp,"timestamp"));
            if (httpRsp.jsonPath().getString("result") != null){
//                httpRsp.jsonPath().getObject("result",Result.class);
                rsp.setResult(HTTPRspUtils.extractObjectFromResponse(httpRsp,"result", Result.class));
            }
        }
        return rsp;
    }

    public static <T> void verifyExpectRst(T expect, Rsp<T> parsedRsp){
        Assert.assertNotNull(parsedRsp, "check parsedRsp.");
        Assert.assertNotNull(parsedRsp.isSuccess(), "check status code.");
        Assert.assertEquals(parsedRsp.getRst(), expect, "check detailed result.");
    }

    public static void verifyError(int statusCode, Error expect, Rsp parsedRsp){
        Assert.assertNotNull(parsedRsp, "check parsedRsp.");
        Assert.assertEquals(parsedRsp.getCode(), statusCode, "check status code.");
        Assert.assertNotNull(parsedRsp.getErrors(), "check error list.");
        Assert.assertTrue(errorContains(expect, parsedRsp.getErrors()), "check expect error.");
    }

    public static boolean errorContains(Error actual, List<Error> errors) {
        boolean match = false;
        for (Error e : errors) {
            if (actual.getError_code().equals(e.getError_code())
                    && actual.getMessage().contains(e.getMessage()) && (actual.getHelp_url() != null && actual.getHelp_url().equals(e.getHelp_url()))) {
                match = true;
            }
        }

        return match;
    }

    public static <T> T extractObjectFromResponse(Response response, String targetPath, Class<T> objectType) {
        return extractObjectFromResponse(response,targetPath,objectType,true);
    }

    public static <T> T extractObjectFromResponse(Response response, String targetPath, Class<T> objectType, boolean isObject) {
        T actual = null;
        try {
            if(isObject){
                //从根元素中提取指定参数
                JsonPath path = response.jsonPath();
                //提取objectType中的值
                actual = path.getObject(targetPath, objectType);
            }else {
                // 未来response内为非object的项，也非Object的项，可能还是会需要修改
                if(objectType.getName().equals("java.lang.String")){
                    actual = (T) response.asString();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return actual;
    }

    /**
     * 从json格式的字符串中解析制定类
     * @param s：待解析的字符串格式的json数据
     * @param path：解析，无需使用$.  直接从根节点字段即可
     * @param objectType：解析对象
     * @param <T>
     * @return
     */
    public static <T> T extractObjectFromString(String s ,String path ,Class<T> objectType){
        T actual = null;
        try {
            JsonPath jsonPath = new JsonPath(s);
            actual = jsonPath.getObject(path,objectType);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return actual;
    }

    public static String extractStringResponse(Response response, String targetPath) {
        String actual = null;
        try {
            //从根元素中提取指定参数
            JsonPath path = response.jsonPath();
            //提取objectType中的值
            actual = path.getString(targetPath);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return actual;
    }

    public static <T> List<T> extractListFromResponse(Response response, String targetPath, Class<T> objectType) {
        List<T> actual = null;
        try {
            JsonPath path = response.jsonPath();
            actual = path.getList(targetPath, objectType);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return actual;
    }

    public static List<Error> extractRspError(final Response response){
        return extractListFromResponse(response, "errors", Error.class);
    }


    public static void compareStatusCode(final Response response, int expectStatusCode) {
        response.then().assertThat().statusCode(expectStatusCode);
    }

    public static void statusLineContains(final Response response, String expect) {
        response.then().assertThat().statusLine(containsString(expect));
    }

    public static void containsResponseError(final Response response, int expectStatusCode, final Error expect) {
        compareStatusCode(response, expectStatusCode);
        containsKeyError(response, expect);
    }

    public static void containsKeyError(final Response response, final Error expect) {
        if (expect != null) {
            assertThat(response, Matchers.notNullValue());
            response.then().assertThat().
                    body("errors.error_code", Matchers.hasItem(Matchers.containsStringIgnoringCase(expect.getError_code()))).
                    body("errors.message", Matchers.hasItem(Matchers.containsStringIgnoringCase(expect.getMessage()))).
                    body("errors.help_url", Matchers.hasItem(expect.getHelp_url()));
        }
    }

//    public static void itemEquals(Response response, String rootPath, String subPath, String expectJson){
//        Map<String, Object> rspMap = response.path(rootPath);
//        Assert.assertTrue(rspMap.containsKey(subPath));
//        Assert.assertEquals(JsonUtil.toJson(rspMap.get(subPath)), expectJson);
//    }
//
//    public static void itemContains(Response response, String rootPath, String subPath, String expectJson){
//        Map<String, Object> jobInfoInMap = response.path(rootPath);
//        Assert.assertTrue(jobInfoInMap.containsKey(subPath));
//        assertThat(JsonUtil.toJson(jobInfoInMap.get(subPath)), Matchers.containsString(expectJson));
//    }

    public static void itemNonExistence(Response response, String rootPath, String subPath){
        Map<String, Object> jobInfoInMap = response.path(rootPath);
        Assert.assertFalse(jobInfoInMap.containsKey(subPath));
    }

    public static <T> void getComponentClass(Class<T> objectType){
        System.out.println(objectType.getName());
        System.out.println(objectType.isPrimitive());
    }

    public static void main(String[] args) {
        getComponentClass(Integer.class);
    }


}
